﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using starLiGHT;

#endregion

#region COPYRIGHT

/*
    Copyright (c) 2008, 2009, 2010 
        Roland Rosenkranz (Glatzemann@email.de)
*/

#endregion

#region LICENSE

/*
    This file is part of starLiGHT.Collision.

    starLiGHT.Collision is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    starLiGHT.Collision is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with starLiGHT.Collision.  If not, see <http://www.gnu.org/licenses/>.

    
    ADDITIONAL (commercial) LICENSES for starLiGHT.Collision are available on request.
*/

#endregion

#region Box2D Copyright
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#endregion

#region Version Stuff
// **************[ starLiGHT.Engine SVN ]**********************
// * $Rev:: 1486                  $:  Revision of last commit *
// * $Author:: glatzemann         $:  Author of last commit   *
// * $Date:: 2010-10-08 15:55:47 #$:  Date of last commit     *
// ************************************************************

// **************[ Box2D-Repository Info ]*********************
// Header-File: http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Dynamics/Joints/PrismaticJoint.h
// Revision   : r60
// Change-Date: 2010-03-01
//
// Source-File: http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Dynamics/Joints/PrismaticJoint.cpp
// Revision   : r28
// Change-Date: 2009-11-23
//
// Status     : Finished!
#endregion

namespace starLiGHT.Physic.TwoD
{
    /// <summary>Prismatic joint definition. This requires defining a line of
    /// motion using an axis and an anchor point. The definition uses local
    /// anchor points and a local axis so that the initial configuration
    /// can violate the constraint slightly. The joint translation is zero
    /// when the local anchor points coincide in world space. Using local
    /// anchors and a local axis helps when saving and loading a game.
    /// </summary>
    /// <remarks>At least one body should be dynamic with a non-fixed rotation.</remarks>
    public class PrismaticJointDef : JointDef
    {
	    public PrismaticJointDef()
	    {
		    type = JointType.PRISMATIC;
		    localAxis1 = new Vector2(1.0f, 0.0f);
		    enableLimit = false;
		    enableMotor = false;
	    }

        /// <summary>Initialize the bodies, anchors, axis, and reference angle using the world
	    /// anchor and world axis.</summary>
	    public void Initialize(Body body1, Body body2, Vector2 anchor, Vector2 axis)
        {
	        this.body1 = body1;
	        this.body2 = body2;
	        localAnchor1 = body1.GetLocalPoint(anchor);
	        localAnchor2 = body2.GetLocalPoint(anchor);
	        localAxis1 = body1.GetLocalVector(axis);
	        referenceAngle = body2.Angle - body1.Angle;
        }

        /// <summary>The local anchor point relative to body1's origin.</summary>
	    public Vector2 localAnchor1;

        /// <summary>The local anchor point relative to body2's origin.</summary>
	    public Vector2 localAnchor2;

        /// <summary>The local translation axis in body1.</summary>
	    public Vector2 localAxis1;

        /// <summary>The constrained angle between the bodies: body2_angle - body1_angle.</summary>
	    public float referenceAngle;

        /// <summary>Enable/disable the joint limit.</summary>
	    public bool enableLimit;

        /// <summary>The lower translation limit, usually in meters.</summary>
	    public float lowerTranslation;

        /// <summary>The upper translation limit, usually in meters.</summary>
	    public float upperTranslation;

        /// <summary>Enable/disable the joint motor.</summary>
	    public bool enableMotor;

        /// <summary>The maximum motor torque, usually in N-m.</summary>
	    public float maxMotorForce;

        /// <summary>The desired motor speed in radians per second.</summary>
	    public float motorSpeed;
    };

    /// <summary>A prismatic joint. This joint provides one degree of freedom: translation
    /// along an axis fixed in body1. Relative rotation is prevented. You can
    /// use a joint limit to restrict the range of motion and a joint motor to
    /// drive the motion or to model joint friction.</summary>
    public class PrismaticJoint : Joint
    {
	    public override Vector2 GetAnchorA()
        {
            return m_body1.GetWorldPoint(ref m_localAnchor1);
        }

	    public override Vector2 GetAnchorB()
        {
            return m_body2.GetWorldPoint(ref m_localAnchor2);
        }

	    public override Vector2 GetReactionForce(float inv_dt)
        {
            return inv_dt * (m_impulse.X * m_perp + (m_motorImpulse + m_impulse.Z) * m_axis);
        }

        public override float GetReactionTorque(float inv_dt)
        {
            return inv_dt * m_impulse.Y;
        }

        /// <summary>Get the current joint translation, usually in meters.</summary>
	    public float GetJointTranslation()
        {
	        Body b1 = m_body1;
	        Body b2 = m_body2;

	        Vector2 p1 = b1.GetWorldPoint(ref m_localAnchor1);
	        Vector2 p2 = b2.GetWorldPoint(ref m_localAnchor2);
	        Vector2 d = p2 - p1;
	        Vector2 axis = b1.GetWorldVector(m_localXAxis1);

	        float translation = Vector2.Dot(d, axis);
	        return translation;
        }

        /// <summary>Get the current joint translation speed, usually in meters per second.</summary>
	    public float GetJointSpeed()
        {
	        Body b1 = m_body1;
	        Body b2 = m_body2;

	        Vector2 r1 = Math.Mul(b1.Transform.R, m_localAnchor1 - b1.LocalCenter);
	        Vector2 r2 = Math.Mul(b2.Transform.R, m_localAnchor2 - b2.LocalCenter);
	        Vector2 p1 = b1.m_sweep.c + r1;
	        Vector2 p2 = b2.m_sweep.c + r2;
	        Vector2 d = p2 - p1;
	        Vector2 axis = b1.GetWorldVector(m_localXAxis1);

	        Vector2 v1 = b1.m_linearVelocity;
	        Vector2 v2 = b2.m_linearVelocity;
	        float w1 = b1.m_angularVelocity;
	        float w2 = b2.m_angularVelocity;

	        float speed = Vector2.Dot(d, Vector2Extensions.Cross(w1, axis)) + Vector2.Dot(axis, v2 + Vector2Extensions.Cross(w2, r2) - v1 - Vector2Extensions.Cross(w1, r1));
	        return speed;
        }

        /// <summary>Is the joint limit enabled?</summary>
	    public bool IsLimitEnabled()
        {
            return m_enableLimit;
        }

        /// <summary>Enable/disable the joint limit.</summary>
	    public void EnableLimit(bool flag)
        {
            m_body1.Awake = true;
            m_body2.Awake = true;
            m_enableLimit = flag;
        }

        /// <summary>Get the lower joint limit, usually in meters.</summary>
	    public float GetLowerLimit()
        {
            return m_lowerTranslation;
        }

        /// <summary>Get the upper joint limit, usually in meters.</summary>
	    public float GetUpperLimit()
        {
            return m_upperTranslation;
        }

        /// <summary>Set the joint limits, usually in meters.</summary>
	    public void SetLimits(float lower, float upper)
        {
	        System.Diagnostics.Debug.Assert(lower <= upper);
            m_body1.Awake = true;
            m_body2.Awake = true;
            m_lowerTranslation = lower;
	        m_upperTranslation = upper;
        }

        /// <summary>Is the joint motor enabled?</summary>
	    public bool IsMotorEnabled()
        {
            return m_enableMotor;
        }

        /// <summary>Enable/disable the joint motor.</summary>
	    public void EnableMotor(bool flag)
        {
            m_body1.Awake = true;
            m_body2.Awake = true;
            m_enableMotor = flag;
        }

        /// <summary>Set the motor speed, usually in meters per second.</summary>
	    public void SetMotorSpeed(float speed)
        {
            m_body1.Awake = true;
            m_body2.Awake = true;
            m_motorSpeed = speed;
        }

        /// <summary>Get the motor speed, usually in meters per second.</summary>
	    public float GetMotorSpeed()
        {
            return m_motorSpeed;
        }

        /// <summary>Set the maximum motor force, usually in N.</summary>
	    public void SetMaxMotorForce(float force)
        {
            m_body1.Awake = true;
            m_body2.Awake = true;
            m_maxMotorForce = 1.0f * force;
        }

        /// <summary>Get the current motor force given the inverse time step, usually in N.</summary>
        public float GetMotorForce(float inv_dt)
        {
            return inv_dt * m_motorImpulse;
        }

	    public PrismaticJoint(PrismaticJointDef def)
            : base(def)
        {
	        m_localAnchor1 = def.localAnchor1;
	        m_localAnchor2 = def.localAnchor2;
	        m_localXAxis1 = def.localAxis1;
	        m_localYAxis1 = Vector2Extensions.Cross(1.0f, m_localXAxis1);
	        m_refAngle = def.referenceAngle;

	        m_lowerTranslation = def.lowerTranslation;
	        m_upperTranslation = def.upperTranslation;
	        m_maxMotorForce = def.maxMotorForce;
	        m_motorSpeed = def.motorSpeed;
	        m_enableLimit = def.enableLimit;
	        m_enableMotor = def.enableMotor;
	        m_limitState = LimitState.INACTIVE;
        }

	    internal override void InitVelocityConstraints(TimeStep step)
        {
	        Body b1 = m_body1;
	        Body b2 = m_body2;

	        m_localCenter1 = b1.LocalCenter;
	        m_localCenter2 = b2.LocalCenter;

	        Transform xf1 = b1.Transform;
	        Transform xf2 = b2.Transform;

	        // Compute the effective masses.
	        Vector2 r1 = Math.Mul(xf1.R, m_localAnchor1 - m_localCenter1);
	        Vector2 r2 = Math.Mul(xf2.R, m_localAnchor2 - m_localCenter2);
	        Vector2 d = b2.m_sweep.c + r2 - b1.m_sweep.c - r1;

	        m_invMass1 = b1.m_invMass;
	        m_invI1 = b1.m_invI;
	        m_invMass2 = b2.m_invMass;
	        m_invI2 = b2.m_invI;

	        // Compute motor Jacobian and effective mass.
	        {
		        m_axis = Math.Mul(xf1.R, m_localXAxis1);
		        m_a1 = Vector2Extensions.Cross(d + r1, m_axis);
		        m_a2 = Vector2Extensions.Cross(r2, m_axis);

		        m_motorMass = m_invMass1 + m_invMass2 + m_invI1 * m_a1 * m_a1 + m_invI2 * m_a2 * m_a2;
                if (m_motorMass > PhysicSettings.FLT_EPSILON)
                {
                    m_motorMass = 1.0f / m_motorMass;
                }
	        }

	        // Prismatic constraint.
	        {
		        m_perp = Math.Mul(xf1.R, m_localYAxis1);

		        m_s1 = Vector2Extensions.Cross(d + r1, m_perp);
		        m_s2 = Vector2Extensions.Cross(r2, m_perp);

		        float m1 = m_invMass1, m2 = m_invMass2;
		        float i1 = m_invI1, i2 = m_invI2;

		        float k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
		        float k12 = i1 * m_s1 + i2 * m_s2;
		        float k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;
		        float k22 = i1 + i2;
                if (k22 == 0.0f)
                {
                    k22 = 1.0f;
                }
		        float k23 = i1 * m_a1 + i2 * m_a2;
		        float k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;

		        m_K.col1 = new Vector3(k11, k12, k13);
		        m_K.col2 = new Vector3(k12, k22, k23);
		        m_K.col3 = new Vector3(k13, k23, k33);
	        }

	        // Compute motor and limit terms.
	        if (m_enableLimit)
	        {
		        float jointTranslation = Vector2.Dot(m_axis, d);
		        if (System.Math.Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * PhysicSettings.LinearSlop)
		        {
			        m_limitState = LimitState.EQUAL;
		        }
		        else if (jointTranslation <= m_lowerTranslation)
		        {
                    if (m_limitState != LimitState.AT_LOWER)
			        {
                        m_limitState = LimitState.AT_LOWER;
				        m_impulse.Z = 0.0f;
			        }
		        }
		        else if (jointTranslation >= m_upperTranslation)
		        {
                    if (m_limitState != LimitState.AT_UPPER)
			        {
                        m_limitState = LimitState.AT_UPPER;
				        m_impulse.Z = 0.0f;
			        }
		        }
		        else
		        {
                    m_limitState = LimitState.INACTIVE;
			        m_impulse.Z = 0.0f;
		        }
	        }
	        else
	        {
                m_limitState = LimitState.INACTIVE;
                m_impulse.Z = 0.0f;
	        }

	        if (m_enableMotor == false)
	        {
		        m_motorImpulse = 0.0f;
	        }

	        if (step.warmStarting)
	        {
		        // Account for variable time step.
		        m_impulse *= step.dtRatio;
		        m_motorImpulse *= step.dtRatio;

		        Vector2 P = m_impulse.X * m_perp + (m_motorImpulse + m_impulse.Z) * m_axis;
		        float L1 = m_impulse.X * m_s1 + m_impulse.Y + (m_motorImpulse + m_impulse.Z) * m_a1;
		        float L2 = m_impulse.X * m_s2 + m_impulse.Y + (m_motorImpulse + m_impulse.Z) * m_a2;

		        b1.m_linearVelocity -= m_invMass1 * P;
		        b1.m_angularVelocity -= m_invI1 * L1;

		        b2.m_linearVelocity += m_invMass2 * P;
		        b2.m_angularVelocity += m_invI2 * L2;
	        }
	        else
	        {
		        m_impulse = Vector3.Zero;
		        m_motorImpulse = 0.0f;
	        }
        }

        internal override void SolveVelocityConstraints(TimeStep step)
        {
	        Body b1 = m_body1;
	        Body b2 = m_body2;

	        Vector2 v1 = b1.m_linearVelocity;
	        float w1 = b1.m_angularVelocity;
	        Vector2 v2 = b2.m_linearVelocity;
	        float w2 = b2.m_angularVelocity;

	        // Solve linear motor constraint.
            if (m_enableMotor && m_limitState != LimitState.EQUAL)
	        {
		        float Cdot = Vector2.Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;
		        float impulse = m_motorMass * (m_motorSpeed - Cdot);
		        float oldImpulse = m_motorImpulse;
		        float maxImpulse = step.dt * m_maxMotorForce;
		        m_motorImpulse = MathHelper.Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
		        impulse = m_motorImpulse - oldImpulse;

		        Vector2 P = impulse * m_axis;
		        float L1 = impulse * m_a1;
		        float L2 = impulse * m_a2;

		        v1 -= m_invMass1 * P;
		        w1 -= m_invI1 * L1;

		        v2 += m_invMass2 * P;
		        w2 += m_invI2 * L2;
	        }

	        Vector2 Cdot1 = Vector2.Zero;
	        Cdot1.X = Vector2.Dot(m_perp, v2 - v1) + m_s2 * w2 - m_s1 * w1;
	        Cdot1.Y = w2 - w1;

	        if (m_enableLimit && m_limitState != LimitState.INACTIVE)
	        {
		        // Solve prismatic and limit constraint in block form.
		        float Cdot2;
		        Cdot2 = Vector2.Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1;
		        Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2);

		        Vector3 f1 = m_impulse;
		        Vector3 df =  m_K.Solve33(-Cdot);
		        m_impulse += df;

                if (m_limitState == LimitState.AT_LOWER)
		        {
                    m_impulse.Z = System.Math.Max(m_impulse.Z, 0.0f);
		        }
                else if (m_limitState == LimitState.AT_UPPER)
		        {
                    m_impulse.Z = System.Math.Min(m_impulse.Z, 0.0f);
		        }

		        // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
		        Vector2 b = -Cdot1 - (m_impulse.Z - f1.Z) * new Vector2(m_K.col3.X, m_K.col3.Y);
		        Vector2 f2r = m_K.Solve22(b) + new Vector2(f1.X, f1.Y);
		        m_impulse.X = f2r.X;
		        m_impulse.Y = f2r.Y;

		        df = m_impulse - f1;

		        Vector2 P = df.X * m_perp + df.Z * m_axis;
		        float L1 = df.X * m_s1 + df.Y + df.Z * m_a1;
		        float L2 = df.X * m_s2 + df.Y + df.Z * m_a2;

		        v1 -= m_invMass1 * P;
		        w1 -= m_invI1 * L1;

		        v2 += m_invMass2 * P;
		        w2 += m_invI2 * L2;
	        }
	        else
	        {
		        // Limit is inactive, just solve the prismatic constraint in block form.
		        Vector2 df = m_K.Solve22(-Cdot1);
		        m_impulse.X += df.X;
		        m_impulse.Y += df.Y;

		        Vector2 P = df.X * m_perp;
		        float L1 = df.X * m_s1 + df.Y;
		        float L2 = df.X * m_s2 + df.Y;

		        v1 -= m_invMass1 * P;
		        w1 -= m_invI1 * L1;

		        v2 += m_invMass2 * P;
		        w2 += m_invI2 * L2;
	        }

	        b1.m_linearVelocity = v1;
	        b1.m_angularVelocity = w1;
	        b2.m_linearVelocity = v2;
	        b2.m_angularVelocity = w2;
        }

	    internal override bool SolvePositionConstraints(float baumgarte)
        {
            //B2_NOT_USED(baumgarte);

	        Body b1 = m_body1;
	        Body b2 = m_body2;

	        Vector2 c1 = b1.m_sweep.c;
	        float a1 = b1.m_sweep.a;

	        Vector2 c2 = b2.m_sweep.c;
	        float a2 = b2.m_sweep.a;

	        // Solve linear limit constraint.
	        float linearError = 0.0f, angularError = 0.0f;
	        bool active = false;
	        float C2 = 0.0f;

	        Mat22 R1 = new Mat22(a1), R2 = new Mat22(a2);

	        Vector2 r1 = Math.Mul(R1, m_localAnchor1 - m_localCenter1);
	        Vector2 r2 = Math.Mul(R2, m_localAnchor2 - m_localCenter2);
	        Vector2 d = c2 + r2 - c1 - r1;

	        if (m_enableLimit)
	        {
		        m_axis = Math.Mul(R1, m_localXAxis1);

		        m_a1 = Vector2Extensions.Cross(d + r1, m_axis);
		        m_a2 = Vector2Extensions.Cross(r2, m_axis);

		        float translation = Vector2.Dot(m_axis, d);
		        if (System.Math.Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * PhysicSettings.LinearSlop)
		        {
			        // Prevent large angular corrections
			        C2 = MathHelper.Clamp(translation, -PhysicSettings.MaxLinearCorrection, PhysicSettings.MaxLinearCorrection);
			        linearError = System.Math.Abs(translation);
			        active = true;
		        }
		        else if (translation <= m_lowerTranslation)
		        {
			        // Prevent large linear corrections and allow some slop.
			        C2 = MathHelper.Clamp(translation - m_lowerTranslation + PhysicSettings.LinearSlop, -PhysicSettings.MaxLinearCorrection, 0.0f);
			        linearError = m_lowerTranslation - translation;
			        active = true;
		        }
		        else if (translation >= m_upperTranslation)
		        {
			        // Prevent large linear corrections and allow some slop.
			        C2 = MathHelper.Clamp(translation - m_upperTranslation - PhysicSettings.LinearSlop, 0.0f, PhysicSettings.MaxLinearCorrection);
			        linearError = translation - m_upperTranslation;
			        active = true;
		        }
	        }

	        m_perp = Math.Mul(R1, m_localYAxis1);

	        m_s1 = Vector2Extensions.Cross(d + r1, m_perp);
	        m_s2 = Vector2Extensions.Cross(r2, m_perp);

	        Vector3 impulse = Vector3.Zero;
	        Vector2 C1 = Vector2.Zero;
	        C1.X = Vector2.Dot(m_perp, d);
	        C1.Y = a2 - a1 - m_refAngle;

	        linearError = System.Math.Max(linearError, System.Math.Abs(C1.X));
	        angularError = System.Math.Abs(C1.Y);

	        if (active)
	        {
		        float m1 = m_invMass1, m2 = m_invMass2;
		        float i1 = m_invI1, i2 = m_invI2;

		        float k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
		        float k12 = i1 * m_s1 + i2 * m_s2;
		        float k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2;
		        float k22 = i1 + i2;
                if (k22 == 0.0f)
                {
                    k22 = 1.0f;
                }
		        float k23 = i1 * m_a1 + i2 * m_a2;
		        float k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2;

		        m_K.col1 = new Vector3(k11, k12, k13);
		        m_K.col2 = new Vector3(k12, k22, k23);
		        m_K.col3 = new Vector3(k13, k23, k33);

		        Vector3 C = Vector3.Zero;
		        C.X = C1.X;
		        C.Y = C1.Y;
		        C.Z = C2;

		        impulse = m_K.Solve33(-C);
	        }
	        else
	        {
		        float m1 = m_invMass1, m2 = m_invMass2;
		        float i1 = m_invI1, i2 = m_invI2;

		        float k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2;
		        float k12 = i1 * m_s1 + i2 * m_s2;
		        float k22 = i1 + i2;
                if (k22 == 0.0f)
                {
                    k22 = 1.0f;
                }

		        m_K.col1 = new Vector3(k11, k12, 0.0f);
		        m_K.col2 = new Vector3(k12, k22, 0.0f);

		        Vector2 impulse1 = m_K.Solve22(-C1);
		        impulse.X = impulse1.X;
		        impulse.Y = impulse1.Y;
		        impulse.Z = 0.0f;
	        }

	        Vector2 P = impulse.X * m_perp + impulse.Z * m_axis;
	        float L1 = impulse.X * m_s1 + impulse.Y + impulse.Z * m_a1;
	        float L2 = impulse.X * m_s2 + impulse.Y + impulse.Z * m_a2;

	        c1 -= m_invMass1 * P;
	        a1 -= m_invI1 * L1;
	        c2 += m_invMass2 * P;
	        a2 += m_invI2 * L2;

	        // TODO_ERIN remove need for this.
	        b1.m_sweep.c = c1;
	        b1.m_sweep.a = a1;
	        b2.m_sweep.c = c2;
	        b2.m_sweep.a = a2;
	        b1.SynchronizeTransform();
	        b2.SynchronizeTransform();
        	
	        return linearError <= PhysicSettings.LinearSlop && angularError <= PhysicSettings.AngularSlop;
        }

	    public Vector2 m_localAnchor1;
	    public Vector2 m_localAnchor2;
	    public Vector2 m_localXAxis1;
	    public Vector2 m_localYAxis1;
	    public float m_refAngle;

	    public Vector2 m_axis, m_perp;
	    public float m_s1, m_s2;
	    public float m_a1, m_a2;

	    public Mat33 m_K;
	    public Vector3 m_impulse;

	    public float m_motorMass;			// effective mass for motor/limit translational constraint.
	    public float m_motorImpulse;

	    public float m_lowerTranslation;
	    public float m_upperTranslation;
	    public float m_maxMotorForce;
	    public float m_motorSpeed;
    	
	    public bool m_enableLimit;
	    public bool m_enableMotor;
	    public LimitState m_limitState;
    };
}
